home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 14 / Example 14.1 / mouse.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-07-16  |  7.2 KB  |  284 lines

  1. #include "mouse.h"
  2.  
  3. //////////////////////////////////////////////////////////////////////////
  4. //                        RAY                                                //
  5. //////////////////////////////////////////////////////////////////////////
  6.  
  7. RAY::RAY()
  8. {
  9.     org = dir = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
  10. }
  11.  
  12. RAY::RAY(D3DXVECTOR3 o, D3DXVECTOR3 d)
  13. {
  14.     org = o;
  15.     dir = d;
  16. }
  17.  
  18. float RAY::Intersect(MESHINSTANCE iMesh)
  19. {
  20.     if(iMesh.m_pMesh == NULL)return -1.0f;
  21.     return Intersect(iMesh.m_pMesh->m_pMesh);
  22. }
  23.  
  24. float RAY::Intersect(BBOX bBox)
  25. {
  26.     if(D3DXBoxBoundProbe(&bBox.min, &bBox.max, &org, &dir))
  27.         return D3DXVec3Length(&(((bBox.min + bBox.max) / 2.0f) - org));
  28.     else return -1.0f;
  29. }
  30.  
  31. float RAY::Intersect(BSPHERE bSphere)
  32. {
  33.     if(D3DXSphereBoundProbe(&bSphere.center, bSphere.radius, &org, &dir))
  34.         return D3DXVec3Length(&(bSphere.center - org));
  35.     else return -1.0f;
  36. }
  37.  
  38. float RAY::Intersect(ID3DXMesh* mesh)
  39. {
  40.     if(mesh == NULL)return -1.0f;
  41.  
  42.     // Collect only the closest intersection
  43.     BOOL hit;
  44.     DWORD dwFace;
  45.     float hitU, hitV, dist;
  46.     D3DXIntersect(mesh, &org, &dir, &hit, &dwFace, &hitU, &hitV, &dist, NULL, NULL);
  47.  
  48.     if(hit) return dist;
  49.     else return -1.0f;
  50. }
  51.  
  52. //////////////////////////////////////////////////////////////////////////
  53. //                        MOUSE                                            //
  54. //////////////////////////////////////////////////////////////////////////
  55.  
  56. MOUSE::MOUSE()
  57. {
  58.     m_iType = 0;
  59.     m_pMouseTexture = NULL;
  60.     m_pMouseDevice = NULL;
  61.     m_fSpeed = 1.5f;
  62.     m_dwBlock = GetTickCount();
  63. }
  64.  
  65. MOUSE::~MOUSE()
  66. {
  67.     if(m_pMouseDevice != NULL)
  68.         m_pMouseDevice->Release();
  69.  
  70.     if(m_pMouseTexture != NULL)
  71.         m_pMouseTexture->Release();
  72. }
  73.  
  74. void MOUSE::InitMouse(IDirect3DDevice9* Dev, HWND wnd)
  75. {
  76.     try
  77.     {
  78.         m_pDevice = Dev;
  79.  
  80.         //Load texture and init sprite
  81.         D3DXCreateTextureFromFile(m_pDevice, "cursor/cursor.dds", &m_pMouseTexture);
  82.         D3DXCreateSprite(m_pDevice, &m_pSprite);
  83.  
  84.         //Get directinput object
  85.         LPDIRECTINPUT8 directInput = NULL;
  86.  
  87.         DirectInput8Create(GetModuleHandle(NULL),    // Retrieves the application handle
  88.                            0x0800,                    // v.8.0    
  89.                            IID_IDirectInput8,        // Interface ID
  90.                            (VOID**)&directInput,    // Our DirectInput Object
  91.                            NULL);
  92.  
  93.         //Acquire Default System mouse
  94.         directInput->CreateDevice(GUID_SysMouse, &m_pMouseDevice, NULL);        
  95.         m_pMouseDevice->SetDataFormat(&c_dfDIMouse);
  96.         m_pMouseDevice->SetCooperativeLevel(wnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND);
  97.         m_pMouseDevice->Acquire();            
  98.  
  99.         //Get viewport size and init mouse location
  100.         D3DVIEWPORT9 v;
  101.         m_pDevice->GetViewport(&v);
  102.         m_viewport.left = v.X;
  103.         m_viewport.top = v.Y;
  104.         m_viewport.right = v.X + v.Width;
  105.         m_viewport.bottom = v.Y + v.Height;
  106.  
  107.         x = v.X + v.Width / 2.0f;
  108.         y = v.Y + v.Height / 2.0f;
  109.  
  110.         //Release Direct Input Object
  111.         directInput->Release();
  112.  
  113.         //Create Mouse Sphere
  114.         D3DXCreateSphere(m_pDevice, 0.2f, 5, 5, &m_pSphereMesh, NULL);
  115.  
  116.         //Create Ball Material
  117.         m_ballMtrl.Diffuse = D3DXCOLOR(1.0f, 1.0f, 0.0f, 1.0f);
  118.         m_ballMtrl.Specular = m_ballMtrl.Ambient = m_ballMtrl.Emissive = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f);
  119.     }
  120.     catch(...)
  121.     {
  122.         debug.Print("Error in MOUSE::InitMouse()");
  123.     }    
  124. }
  125.  
  126. bool MOUSE::ClickLeft()
  127.     if(GetTickCount() < m_dwBlock)return false;
  128.     return m_mouseState.rgbButtons[0];
  129. }
  130.  
  131. bool MOUSE::ClickRight()
  132. {
  133.     if(GetTickCount() < m_dwBlock)return false;
  134.     return m_mouseState.rgbButtons[1];
  135. }
  136.  
  137. bool MOUSE::WheelUp()
  138. {
  139.     if(GetTickCount() < m_dwBlock)return false;
  140.     return m_mouseState.lZ > 0.0f;
  141. }
  142.  
  143. bool MOUSE::WheelDown()
  144. {
  145.     if(GetTickCount() < m_dwBlock)return false;
  146.     return m_mouseState.lZ < 0.0f;
  147. }
  148.  
  149. bool MOUSE::Over(RECT dest)
  150. {
  151.     if(x < dest.left || x > dest.right)return false;
  152.     if(y < dest.top || y > dest.bottom)return false;
  153.     return true;
  154. }
  155.  
  156. bool MOUSE::PressInRect(RECT dest)
  157. {
  158.     return ClickLeft() && Over(dest);
  159. }
  160.  
  161. void MOUSE::Update(TERRAIN *terrain)
  162. {
  163.     //Retrieve mouse state
  164.     ZeroMemory(&m_mouseState, sizeof(DIMOUSESTATE));
  165.     m_pMouseDevice->GetDeviceState(sizeof(DIMOUSESTATE), &m_mouseState);
  166.  
  167.     //Update pointer
  168.     x += m_mouseState.lX * m_fSpeed;
  169.     y += m_mouseState.lY * m_fSpeed;
  170.  
  171.     //Keep mouse pointer within window
  172.     if(x < m_viewport.left)    x = m_viewport.left;
  173.     if(y < m_viewport.top)    y = m_viewport.top;
  174.     if(x > m_viewport.right)    x = m_viewport.right;
  175.     if(y > m_viewport.bottom)    y = m_viewport.bottom;
  176.  
  177.     if(terrain != NULL)
  178.         CalculateMappos(*terrain);
  179. }
  180.  
  181. void MOUSE::Paint()
  182. {    
  183.     //Draw ball
  184.     D3DXMATRIX world;
  185.     D3DXMatrixTranslation(&world, m_ballPos.x, m_ballPos.y, m_ballPos.z);
  186.     m_pDevice->SetTransform(D3DTS_WORLD, &world);
  187.     m_pDevice->SetMaterial(&m_ballMtrl);
  188.     m_pDevice->SetTexture(0, NULL);
  189.     m_pSphereMesh->DrawSubset(0);
  190.  
  191.     if(m_pMouseTexture != NULL)
  192.     {
  193.         RECT src[] = {{0,0,20,20}, {0,20,20,40}, {20,20,40,40}, {0,40,20,60}, {20,40,40,60}};
  194.  
  195.         m_pSprite->Begin(D3DXSPRITE_ALPHABLEND);
  196.         m_pSprite->Draw(m_pMouseTexture, &src[m_iType], NULL, &D3DXVECTOR3(x, y, 0.0f), 0xffffffff);
  197.         m_pSprite->End();
  198.     }    
  199. }
  200.  
  201. RAY MOUSE::GetRay()
  202. {
  203.     try
  204.     {
  205.         D3DXMATRIX projectionMatrix, viewMatrix, worldViewInverse, worldMatrix;
  206.         
  207.         m_pDevice->GetTransform(D3DTS_PROJECTION, &projectionMatrix);
  208.         m_pDevice->GetTransform(D3DTS_VIEW, &viewMatrix);
  209.         m_pDevice->GetTransform(D3DTS_WORLD, &worldMatrix);
  210.  
  211.         float width = m_viewport.right - m_viewport.left;
  212.         float height = m_viewport.bottom - m_viewport.top;
  213.  
  214.         float angle_x = (((2.0f * x) / width) - 1.0f) / projectionMatrix(0,0);
  215.         float angle_y = (((-2.0f * y) / height) + 1.0f) / projectionMatrix(1,1); 
  216.         
  217.         RAY ray;
  218.         ray.org = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
  219.         ray.dir = D3DXVECTOR3(angle_x, angle_y, 1.0f);
  220.  
  221.         D3DXMATRIX m = worldMatrix * viewMatrix;
  222.         D3DXMatrixInverse(&worldViewInverse, 0, &m);
  223.         D3DXVec3TransformCoord(&ray.org, &ray.org, &worldViewInverse);
  224.         D3DXVec3TransformNormal(&ray.dir, &ray.dir, &worldViewInverse);
  225.         D3DXVec3Normalize(&ray.dir, &ray.dir);
  226.  
  227.         return ray;
  228.     }
  229.     catch(...)
  230.     {
  231.         debug.Print("Error in MOUSE::GetRay()");
  232.     }
  233. }
  234.  
  235. void MOUSE::CalculateMappos(TERRAIN &terrain)
  236. {
  237.     //Get Mouse Ray
  238.     D3DXMATRIX world;
  239.     D3DXMatrixIdentity(&world);
  240.     m_pDevice->SetTransform(D3DTS_WORLD, &world);
  241.     RAY mRay = GetRay();
  242.  
  243.     float minDistance = 10000.0f;
  244.     for(int i=0;i<terrain.m_patches.size();i++)
  245.     {
  246.         if(mRay.Intersect(terrain.m_patches[i]->m_BBox) > 0.0f)
  247.         {
  248.             // Collect only the closest intersection
  249.             BOOL hit;
  250.             DWORD dwFace;
  251.             float hitU, hitV, dist;
  252.             D3DXIntersect(terrain.m_patches[i]->m_pMesh, &mRay.org, &mRay.dir, &hit, &dwFace, &hitU, &hitV, &dist, NULL, NULL);
  253.  
  254.             if(hit && dist < minDistance)
  255.             {
  256.                 minDistance = dist;
  257.                 int tiles = dwFace / 2;        //Two faces to each map tile
  258.                 int tilesPerRow = terrain.m_patches[i]->m_mapRect.right - terrain.m_patches[i]->m_mapRect.left;
  259.                 int y = tiles / tilesPerRow, x = tiles - y * tilesPerRow;
  260.  
  261.                 if(dwFace % 2 == 0)        //Hit upper left face
  262.                 {
  263.                     if(hitU > 0.5f)x++;
  264.                     else if(hitV > 0.5f)y++;
  265.                 }
  266.                 else                    //Hit lower right face
  267.                 {
  268.                     if(hitU + hitV < 0.5f)y++;
  269.                     else if(hitU > 0.5f)x++;
  270.                     else {x++;y++;}
  271.                 }
  272.  
  273.                 m_mappos.Set(terrain.m_patches[i]->m_mapRect.left + x, terrain.m_patches[i]->m_mapRect.top + y);
  274.                 m_ballPos = terrain.GetWorldPos(m_mappos);
  275.             }            
  276.         }
  277.     }    
  278. }
  279.  
  280. void MOUSE::DisableInput(int millisec)
  281. {
  282.     m_dwBlock = GetTickCount() + millisec;
  283. }